/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package jocabulary;

import java.io.*;
import java.util.*;

import javax.xml.parsers.*;

import org.w3c.dom.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

/**
 *
 * @author pit
 */
public class Unit extends DefaultHandler {

    private FileDownloader fd = new FileDownloader();

    private ArrayList vocab = new ArrayList();
    private ArrayList vocabPrepared = new ArrayList();

    private int askedVocab = 0;

    private String unitName;
    private String cleanName;
    private int onlineRevision;
    private int localRevision;
    private boolean isLoaded = false;

    private String baseFolder = "data/";

    private String tempVal;
    private Vocable tempVoc;

    private Document dom;

    Unit(String pUnitName, String pCleanName, int pOnlineRevision) throws IOException {
        unitName = pUnitName;
        cleanName = pCleanName;
        onlineRevision = pOnlineRevision;

        fd.fileExists(unitName+".xml");
    }

    public void loadVocab() {
        vocab.clear();
        if (fileExists()) {
            parseFile();
            if(updateAvailable()) {
                fd.downloadFile(unitName+".xml");
                parseFile();
            }
        } else {
            fd.downloadFile(unitName+".xml");
            parseFile();
        }
        isLoaded = true;
    }


    public String getUnitName() {
        return unitName;
    }

    public String getCleanName() {
        return cleanName;
    }
    
    public int getVocabCount() {
        return vocabPrepared.size();
    }

    public int getAskedCount() {
        return askedVocab;
    }

    public Vocable getVocable(int index) {
        return (Vocable) vocab.get(index);
    }


    private boolean fileExists() {
        File f = new File(baseFolder+unitName+".xml");
        return f.exists();
    }

    private boolean updateAvailable() {
        return (onlineRevision > localRevision);
    }

    private void parseFile() {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        try {
            SAXParser sp = spf.newSAXParser();
            sp.parse((baseFolder+unitName+".xml"), this);
        } catch(Exception e) {
            System.out.println(e);
        }
    }
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        tempVal = "";

        if(qName.equalsIgnoreCase("Vocable")) {
            tempVoc = new Vocable();
            tempVoc.setRequired(Boolean.parseBoolean(attributes.getValue("required")));
            tempVoc.setType(attributes.getValue("type"));
        }
    }
    public void characters(char[] ch, int start, int length) throws SAXException {
        tempVal = new String(ch, start, length);
    }
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if(qName.equalsIgnoreCase("Revision")) {
            localRevision = Integer.parseInt(tempVal);
        } else if(qName.equalsIgnoreCase("Vocable")) {
            vocab.add(tempVoc);
        } else if(qName.equalsIgnoreCase("NativeWord")) {
            tempVoc.setNativeWord(tempVal);
        } else if(qName.equalsIgnoreCase("Translation")) {
            tempVoc.setTranslation(tempVal);
        } else if(qName.equalsIgnoreCase("AlternativeTranslation")) {
            tempVoc.setAlternativeTranslation(tempVal);
        } else if(qName.equalsIgnoreCase("TimesCorrect")) {
            tempVoc.setTimesCorrect(Integer.parseInt(tempVal));
        }
    }

    public void writeFile() {
        if(isLoaded) {
            createDocument();
            createDOMTree();
            saveToFile();
        }
    }
    public void createDocument() {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            dom = db.newDocument();
        } catch(ParserConfigurationException pce) {
            System.out.println(pce);
        }
    }
    public void createDOMTree() {
        Element rootEle = dom.createElement("List");
        dom.appendChild(rootEle);

        Element revisionEle = dom.createElement("Revision");
        Text revisionText = dom.createTextNode(""+onlineRevision);
        revisionEle.appendChild(revisionText);
        rootEle.appendChild(revisionEle);

        Iterator it = vocab.iterator();
        while(it.hasNext()) {
            Vocable v = (Vocable)it.next();
            Element vocEle = createVocabElement(v);
            rootEle.appendChild(vocEle);
        }
    }
    public Element createVocabElement(Vocable v) {
        Element vocEle = dom.createElement("Vocable");
        vocEle.setAttribute("required", String.valueOf(v.getRequired()));
        vocEle.setAttribute("type", v.getType());

        Element nativeWord = dom.createElement("NativeWord");
        Text nativeText = dom.createTextNode(v.getNativeWord());
        nativeWord.appendChild(nativeText);
        vocEle.appendChild(nativeWord);

        Element translation = dom.createElement("Translation");
        Text translationText = dom.createTextNode(v.getTranslation());
        translation.appendChild(translationText);
        vocEle.appendChild(translation);

        Element alternativeTranslation = dom.createElement("AlternativeTranslation");
        Text alternativeText = dom.createTextNode(v.getAlternativeTranslation());
        alternativeTranslation.appendChild(alternativeText);
        vocEle.appendChild(alternativeTranslation);

        Element timesCorrect = dom.createElement("TimesCorrect");
        Text timesText = dom.createTextNode(String.valueOf(v.getTimesCorrect()));
        timesCorrect.appendChild(timesText);
        vocEle.appendChild(timesCorrect);

        return vocEle;
    }
    public void saveToFile() {
        try {
            OutputFormat format = new OutputFormat(dom);
            format.setIndenting(true);
            
            XMLSerializer serializer = new XMLSerializer( new FileOutputStream( new File(baseFolder+unitName+".xml") ), format );
            serializer.serialize(dom);
        } catch(Exception e) {
            System.out.println(e);
        }
    }

    public void prepareQuestions(int pTimesCorrect, boolean pRequired, boolean pRandomAskOrder) {
        vocabPrepared.clear();

        for(int i=0; i<vocab.size(); i++) {
            Vocable v = (Vocable) vocab.get(i);
            if((pTimesCorrect == 3) || (v.getTimesCorrect() <= pTimesCorrect)) {
                if((pRequired && v.getRequired()) || !pRequired) {
                    vocabPrepared.add(v);
                }
            }
        }

        if(pRandomAskOrder)
            Collections.shuffle(vocabPrepared);

        askedVocab = 0;
    }

    public Vocable getNextVocable() throws Exception {
        Vocable v = (Vocable) vocabPrepared.get(askedVocab);
        askedVocab++;
        return v;
    }

}
